module aru_reduce_div (
    input logic                 clk,
    input logic                 rst_n,
          aru_reduce_ctrl_if.in u_aru_ctrl_if,
          aru_reduce_pld_if.in  u_aru_reduce_stage3_if,
          aru_reduce_pld_if.out u_aru_reduce_div_if
);
    // ===== 暂存控制信号 =====
    logic       reduce_m_reg;
    logic       reduce_n_reg;
    logic [1:0] reduce_op_reg;
    idx_t       slice_m_reg;
    idx_t       slice_n_reg;

    // 配置信号握手逻辑
    logic ctrl_rdy, ctrl_vld;
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            ctrl_rdy      <= 1'b1;
            reduce_m_reg  <= 'd0;
            reduce_n_reg  <= 'd0;
            reduce_op_reg <= 'd0;
            slice_m_reg   <= 'd0;
            slice_n_reg   <= 'd0;
        end else if (ctrl_rdy == 1'b0) begin
            if (u_aru_reduce_div_if.vld && u_aru_reduce_div_if.rdy && u_aru_reduce_div_if.sdb.eom && u_aru_reduce_div_if.sdb.eon) begin
                ctrl_rdy <= 1'b1;
            end
        end else begin
            if (u_aru_ctrl_if.vld && u_aru_ctrl_if.rdy) begin
                ctrl_rdy      <= 1'b0;
                reduce_m_reg  <= u_aru_ctrl_if.reduce_m;
                reduce_n_reg  <= u_aru_ctrl_if.reduce_n;
                reduce_op_reg <= u_aru_ctrl_if.reduce_op;
                slice_m_reg   <= u_aru_ctrl_if.slice_m;
                slice_n_reg   <= u_aru_ctrl_if.slice_n;
            end
        end
    end

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            ctrl_vld <= 1'b0;
        end else if (ctrl_vld == 1'b0) begin
            if (u_aru_ctrl_if.vld && u_aru_ctrl_if.rdy) begin
                ctrl_vld <= 1'b1;
            end
        end else begin
            if (u_aru_reduce_stage3_if.vld && u_aru_reduce_stage3_if.rdy && u_aru_reduce_stage3_if.sdb.eom && u_aru_reduce_stage3_if.sdb.eon) begin
                ctrl_vld <= 1'b0;
            end
        end
    end

    // 流水线使能信号
    logic pipeline_en;
    assign pipeline_en = u_aru_reduce_div_if.rdy;

    // 判断操作模式
    logic is_avg;  // 11: mean模式,需要除法
    logic is_sum;  // 10: sum模式,不需要除法但需要FP32->BF16转换
    logic need_convert;  // 需要FP32->BF16转换的模式(sum和avg)

    assign is_avg       = (reduce_op_reg == 2'b11);
    assign is_sum       = (reduce_op_reg == 2'b10);
    assign need_convert = is_avg || is_sum;

    // 计算除数(仅avg模式需要)
    fp32_t divisor_fp32;
    idx_t  divisor_value;

    always_comb begin
        case ({
            reduce_m_reg, reduce_n_reg
        })
            2'b10:   divisor_value = slice_m_reg;  // reduce_m=1, reduce_n=0
            2'b01:   divisor_value = slice_n_reg;  // reduce_m=0, reduce_n=1
            2'b11:   divisor_value = slice_m_reg * slice_n_reg;  // reduce_m=1, reduce_n=1
            default: divisor_value = 16'd1;
        endcase
    end

    // 将除数转换为FP32格式
    always_comb begin
        if (divisor_value == 0) begin
            divisor_fp32.sign = 1'b0;
            divisor_fp32.exp  = 8'd127;  // 1.0 in FP32
            divisor_fp32.mant = 23'd0;
        end else begin
            divisor_fp32 = int_to_fp32(divisor_value);
        end
    end

    // 确定需要处理的数据个数
    localparam int MAX_DATA = `P_ARU * `N0;  // 32
    localparam int NUM_DIVIDERS = 8;

    // ==================== 除法器实例化 ====================
    fp32_t div_X_reg    [NUM_DIVIDERS];
    fp32_t div_Y_reg    [NUM_DIVIDERS];
    fp32_t div_X        [NUM_DIVIDERS];
    fp32_t div_Y        [NUM_DIVIDERS];
    fp32_t div_R        [NUM_DIVIDERS];
    logic  div_out_valid[NUM_DIVIDERS];

    // 除法器输入打拍 缓解除数乘法计算的时序
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (int i = 0; i < NUM_DIVIDERS; i++) begin
                div_X_reg[i] <= 32'h00000000;
                div_Y_reg[i] <= 32'h3F800000;  // 1.0 in FP32
            end
        end else if (pipeline_en) begin
            for (int i = 0; i < NUM_DIVIDERS; i++) begin
                if (is_avg) begin
                    // Mean模式:需要除法
                    div_X_reg[i] <= u_aru_reduce_stage3_if.dat[i].fp32;
                    div_Y_reg[i] <= divisor_fp32;
                end else begin
                    // 其他模式:保持寄存器值
                    div_X_reg[i] <= div_X_reg[i];
                    div_Y_reg[i] <= div_Y_reg[i];
                end
            end
        end
    end

    // 将寄存器输出连接到除法器输入
    always_comb begin
        for (int i = 0; i < NUM_DIVIDERS; i++) begin
            div_X[i] = div_X_reg[i];
            div_Y[i] = div_Y_reg[i];
        end
    end

    genvar i;
    generate
        for (i = 0; i < NUM_DIVIDERS; i++) begin : gen_dividers
            fp32_fpdiv_wrapper u_div (
                .clk         (clk),
                .rst         (~rst_n),
                .clock_enable(pipeline_en),
                .in_valid    (pipeline_en),
                .X           (div_X[i]),
                .Y           (div_Y[i]),
                .R           (div_R[i]),
                .out_valid   (div_out_valid[i])
            );
        end
    endgenerate

    // ==================== sum模式的FP32数据延迟对齐 ====================
    localparam int INPUT_REG_LATENCY = 1;
    localparam int DIV_LATENCY = 12;
    localparam int CONV_LATENCY = 1;
    localparam int SUM_LATENCY = INPUT_REG_LATENCY + DIV_LATENCY;
    localparam int TOTAL_LATENCY = INPUT_REG_LATENCY + DIV_LATENCY + CONV_LATENCY;
    // sum模式需要将FP32数据延迟SUM_LATENCY周期,以对齐除法器延迟
    fp32_t sum_fp32_delayed[SUM_LATENCY-1:0][NUM_DIVIDERS];

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (int stage = 0; stage < SUM_LATENCY; stage++) begin
                for (int i = 0; i < NUM_DIVIDERS; i++) begin
                    sum_fp32_delayed[stage][i] <= 32'h00000000;
                end
            end
        end else if (pipeline_en) begin
            // Stage 0: 采样输入
            for (int i = 0; i < NUM_DIVIDERS; i++) begin
                sum_fp32_delayed[0][i] <= u_aru_reduce_stage3_if.dat[i].fp32;
            end
            // Stage 1 -> SUM_LATENCY-1: 延迟传递
            for (int stage = 1; stage < SUM_LATENCY; stage++) begin
                for (int i = 0; i < NUM_DIVIDERS; i++) begin
                    sum_fp32_delayed[stage][i] <= sum_fp32_delayed[stage-1][i];
                end
            end
        end
    end

    // ==================== FP32 to BF16 转换 ====================
    logic [31:0] fp32_conv_in     [NUM_DIVIDERS];
    logic [15:0] bf16_conv_out    [NUM_DIVIDERS];
    logic [15:0] bf16_conv_out_reg[NUM_DIVIDERS];

    // FP32 to BF16 转换模块实例化 - 只需要8个
    generate
        for (i = 0; i < NUM_DIVIDERS; i++) begin : gen_fp32_to_bf16
            // 根据模式选择输入源
            always_comb begin
                if (is_avg) begin
                    // avg模式:使用除法器结果
                    fp32_conv_in[i] = div_R[i];
                end else begin
                    // sum模式:使用延迟对齐后的FP32输入
                    fp32_conv_in[i] = sum_fp32_delayed[SUM_LATENCY-1][i];
                end
            end

            fp32_to_bf16 u_fp32_to_bf16 (
                .fp32_data(fp32_conv_in[i]),
                .bf16_data(bf16_conv_out[i])
            );
        end
    endgenerate

    // 对转换结果打拍
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (int i = 0; i < NUM_DIVIDERS; i++) begin
                bf16_conv_out_reg[i] <= 16'h0000;
            end
        end else if (pipeline_en) begin
            for (int i = 0; i < NUM_DIVIDERS; i++) begin
                bf16_conv_out_reg[i] <= bf16_conv_out[i];
            end
        end
    end

    // ==================== Bypass 数据流水线 ====================

    logic            pipe_vld[TOTAL_LATENCY-1:0];
    aru_reduce_pld_t pipe_pld[TOTAL_LATENCY-1:0];

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (int i = 0; i < TOTAL_LATENCY; i++) begin
                pipe_vld[i] <= 1'b0;
                pipe_pld[i] <= '0;
            end
        end else if (pipeline_en) begin
            // Stage 0
            pipe_vld[0]     <= u_aru_reduce_stage3_if.vld;
            pipe_pld[0].dat <= u_aru_reduce_stage3_if.dat;
            pipe_pld[0].msk <= u_aru_reduce_stage3_if.msk;
            pipe_pld[0].sdb <= u_aru_reduce_stage3_if.sdb;
            // Stage 1 -> TOTAL_LATENCY-1
            for (int i = 1; i < TOTAL_LATENCY; i++) begin
                pipe_vld[i] <= pipe_vld[i-1];
                pipe_pld[i] <= pipe_pld[i-1];
            end
        end
    end

    // ==================== 输出逻辑 ====================
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            u_aru_reduce_div_if.vld <= '0;
            u_aru_reduce_div_if.dat <= '0;
            u_aru_reduce_div_if.msk <= '0;
            u_aru_reduce_div_if.sdb <= '0;
        end else if (pipeline_en) begin
            // sideband和vld使用延迟后的数据
            u_aru_reduce_div_if.vld <= pipe_vld[TOTAL_LATENCY-1];
            u_aru_reduce_div_if.sdb <= pipe_pld[TOTAL_LATENCY-1].sdb;

            if (need_convert) begin
                // sum或avg模式:前8个数据使用BF16转换结果
                for (int i = 0; i < NUM_DIVIDERS; i++) begin
                    // 正确赋值联合体中的bf16成员
                    u_aru_reduce_div_if.dat[i].bf16.dat <= bf16_conv_out_reg[i];
                    u_aru_reduce_div_if.dat[i].bf16.rsv <= 16'h0000;
                    u_aru_reduce_div_if.msk[i]          <= pipe_pld[TOTAL_LATENCY-1].msk[i];
                end
                // 剩余数据直接传递
                for (int i = NUM_DIVIDERS; i < MAX_DATA; i++) begin
                    u_aru_reduce_div_if.dat[i] <= pipe_pld[TOTAL_LATENCY-1].dat[i];
                    u_aru_reduce_div_if.msk[i] <= pipe_pld[TOTAL_LATENCY-1].msk[i];
                end
            end else begin
                // Bypass模式:直接输出延迟后的数据
                u_aru_reduce_div_if.dat <= pipe_pld[TOTAL_LATENCY-1].dat;
                u_aru_reduce_div_if.msk <= pipe_pld[TOTAL_LATENCY-1].msk;
            end
        end
    end

    // 配置接口握手
    assign u_aru_ctrl_if.rdy          = ctrl_rdy;

    // Stage3接口握手
    assign u_aru_reduce_stage3_if.rdy = u_aru_reduce_div_if.rdy & ctrl_vld;

    // ==================== 辅助函数:整数转FP32 ====================
    function automatic fp32_t int_to_fp32(input idx_t value);
        fp32_t        result;
        logic  [ 7:0] exp;
        logic  [22:0] mant;
        int           msb_position;
        int           shift;
        logic  [39:0] shval;

        // 默认返回 +0.0
        result.sign = 1'b0;
        result.exp  = 8'd0;
        result.mant = 23'd0;

        if (value != 16'd0) begin
            // 找MSB位置 - 使用casez(优先编码器)
            casez (value)
                16'b1???????????????: msb_position = 15;
                16'b01??????????????: msb_position = 14;
                16'b001?????????????: msb_position = 13;
                16'b0001????????????: msb_position = 12;
                16'b00001???????????: msb_position = 11;
                16'b000001??????????: msb_position = 10;
                16'b0000001?????????: msb_position = 9;
                16'b00000001????????: msb_position = 8;
                16'b000000001???????: msb_position = 7;
                16'b0000000001??????: msb_position = 6;
                16'b00000000001?????: msb_position = 5;
                16'b000000000001????: msb_position = 4;
                16'b0000000000001???: msb_position = 3;
                16'b00000000000001??: msb_position = 2;
                16'b000000000000001?: msb_position = 1;
                16'b0000000000000001: msb_position = 0;
                default:              msb_position = -1;
            endcase

            if (msb_position >= 0) begin
                // 指数 = 127 + MSB位置
                exp = 8'(127 + msb_position);

                // 规范化:将数值左移或右移,使MSB对齐到bit[23]位置
                if (msb_position >= 23) begin
                    shift = msb_position - 23;
                    shval = {24'd0, value} >> shift;
                end else begin
                    shift = 23 - msb_position;
                    shval = {24'd0, value} << shift;
                end

                // 提取尾数(bit[22:0],隐含1已被移除)
                mant        = shval[22:0];

                // 打包结果
                result.sign = 1'b0;  // 正数
                result.exp  = exp;
                result.mant = mant;
            end
        end

        return result;
    endfunction

endmodule
